Skip to content

fix(integration-branch): bound every Git read to one budget - #8363

Open
gcl-coder wants to merge 3 commits into
loopx-project:mainfrom
gcl-coder:fix/integration-branch-git-budget
Open

gcl-coder wants to merge 3 commits into
loopx-project:mainfrom
gcl-coder:fix/integration-branch-git-budget

Conversation

@gcl-coder

Copy link
Copy Markdown
Contributor

动机 / Motivation

repository-change-window 与 change-quality 的 Git 读取已经有预算(#8362、#8169),但整合分支这条路径还没有:loopx/capabilities/integration_branch/core.py 的 _git() 是所有读取的唯一入口,configure_integration_branch、integration_branch_status、sync_integration_branch 都经由它执行 rev-parse、check-ignore、worktree list、fetch、merge、update-ref 等命令,底层是一个没有上限的 subprocess.run。

仓库卡在陈旧 index.lock、网络挂载或卡住的 fsmonitor helper 上时,这条调用链既不返回也不报错;放在 hook 或自动化里就会把 Git 操作本身一起挂住。

改动思路 / Approach

_git() 仍是唯一入口,只在这一处加上预算:

  • 每次读取在独立 session 中 Popen,用 communicate(timeout=GIT_READ_TIMEOUT_SECONDS) 等待,预算 10 秒。
  • 超时或收到取消时,调用 main 上已有的共享 retire_owned_process,在同一 deadline 内回收这次读取拥有的进程组、关闭未排空的管道;随后抛 IntegrationBranchError。
  • 正常读取仍返回同样的文本输出、退出码;check=True 时非零退出仍按 stderr 给出原有的错误细节。
  • 10 秒是每次读取重新分配的预算,不是整条命令的共享 deadline。

与 #8169、#8362 一样,这里只复用既有 owner:Git 读取的接口属于本能力,进程与管道的回收属于共享 runtime。

具体改动 / Changes

  • _git():从裸 subprocess.run 改为独立 session 的 Popen + 有界 communicate;超时与取消都先回收再抛出/继续传播。
  • _retire_owned_read():只回收本次读取拥有的会话,清理异常不替换本次读取的 timeout 或取消结果。
  • tests/capabilities/test_integration_branch_git_budget.py:新增三条用例——正常读取保留文本与退出码、永不作答的假 git 在预算内拒绝且心跳停止、Git 无法启动时仍抛 OSError。

对主干的风险 / Risks

  • 本地 tests/capabilities/test_integration_branch.py 加新增三条共 18 项全部通过(18 passed)。
  • 原生 Windows 未执行;Windows 分支的 taskkill 与 Job Object 路径由共享 runtime 承担,其行为已在 fix(change-quality): hold every Git read of the scope to one budget #8169 的注入用例中验证,本 PR 沿用同一入口。
  • 10 秒预算可能拒绝一个合法但极慢的读取(例如超大仓库上的 fetch);这是有意的 fail-closed 边界,调用方会拿到明确错误,而不是无限等待。
  • 不改 plan schema、status/sync 的输出结构、CLI 参数或合并权限。

我的整体评价 / Verdict

范围限定在一处 Git 入口,复用已验证的共享回收路径,正常结果与错误细节都保持不变。原生 Windows 与最慢读取的取舍仍待评审确认。

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

REQUEST_CHANGES:1 个 P2。默认预算可打断已经登记的临时 worktree,但异常路径没有撤销登记;成功重试后仍留下失效记录。

动机 / Motivation

维护多条已评审分支的开发者需要整合当前 source heads,同时在 Git helper 卡住时得到明确失败。旧同步可能无限等待;新实现让单次 Git 操作超时退出,正常情况下仍生成候选、发布本地整合分支并读回回执。可验证的目标是有界失败后仍能安全继续;本 PR 不改变 plan、分支顺序、source refs 或远端/PR 权限,临时 worktree 清理仍是这个目标的一部分。目前尚缺超时后撤销本次 candidate 登记的恢复路径。

改动思路 / Approach

唯一 Git 入口 _git 保持既有文本和错误处理,并将 communicate 等待限制到每次 10 秒;共享 process_runtime.retire_owned_process 负责已拥有进程组和管道的有界回收。这是既有 Python Git adapter 的 IO 边界,不是新增的 Core 决策能力。与 change_quality.scope、并行 #8362 相比,进程回收 owner 已复用,文本/bytes 与能力异常不必强行合成新框架。

但这里的 _git 同时执行 fetch、merge、worktree add/remove、reset 和 update-ref,并不都是读取。当前切片必须把新超时接入已有写操作的失败清理;仅杀进程不等于撤销 Git 已完成的登记。无需扩大成新事务系统:在既有 _build_candidate 里补本次 candidate 的有界清理并保留原异常,即可完成这个切片。不修改 plan schema、source refs、远端或 PR 权限。

具体改动 / Changes

全 PR 为 2 文件,+153/-6;生产文件 +62/-6,新增测试 91 行。规范依据 loopx/capabilities/integration_branch/README.md,不可变版本 c63a8f9cfc023ff22f39db5cb8b734da7653e83d,原文未被本 PR 改写。configure 的 preview-first 和 ignored plan、boundary 的不 push/不改 source branch 均通过真实 CLI;preview-and-sync 的临时 worktree 清理在下面反例中未满足,需修复后重验。

关键代码讲解

  1. _git L47 将每次 Git 操作放入独立 POSIX session,正常返回维持 UTF-8 replace 和原非零诊断。L73–79 的新 TimeoutExpired 分支回收进程后立即抛 IntegrationBranchError;它也可能中断已有写操作,不能只按读取失败理解。
  2. _retire_owned_read L30 复用共享回收函数,不把清理异常替换成成功结果。这个边界能限制等待,但并不知道 Git 是否已在 common dir 中登记 worktree。
  3. _build_candidate L605 先执行 worktree add,直到其返回后才把 added 设为 True。真实 post-checkout hook 是登记完成之后运行的;此时被新预算中断,finally 看到 added=False,跳过 worktree remove,却删除临时目录,留下 .git/worktrees 中指向不存在目录的条目。

对主干的风险 / Risks

[P2] 超时后清理本次 worktree 登记

独立真实 Git/公开 CLI 反例:建立 main、feature-a 和 ignored plan,先同步;推进 feature-a,再安装内容为 #!/bin/sh 加 sleep 11.5 的 .git/hooks/post-checkout,执行 loopx --format json integration-branch sync --repo-path <fixture> --execute,保留默认 10 秒。不可变 base 约 13.57 秒成功、0 个失效 worktree;本 head 约 11.54 秒返回 rc=2/invalid_state 和 worktree add 超时,git worktree list --porcelain 多出 1 个 prunable gitdir file points to non-existent location 条目。移除 hook 后重试同步成功,该条目依然存在。周期同步每次遭遇同样超时都会累积本能力自己的失效登记,不能由“已退出”或“重试成功”证明资源已收回。

最小修复:让 _build_candidate 在 worktree add 已产生部分效果而抛错时,也撤销本次 candidate 登记;清理即使出错也要执行目录收尾并保留原超时。只处理本次拥有的路径,不全局 prune 其他工作。新增真实 Git 的慢 post-checkout 回归,断言超时后 worktree 清单、临时目录、integration branch 和 last_sync 均符合预期,再验证解除故障后的成功与重复执行。

PASS:77 tests,1 skipped;新 3 条预算测试和原 integration、共享 process runtime 测试均通过。独立 CLI 的 configure preview/execute/replay、drift status、sync preview/execute/replay、in-sync status 和越界 plan 拒绝,共 9 项的完整 JSON/退出码在 base/head 相同;上面的写中断反例 FAIL,现有 fake-git 测试没有覆盖登记后 hook 阻塞。

本地 standard premerge 的 6 项直接检查和 2 项 catalog 检查通过。另行执行的 maintainability ratchet 仍 FAIL:Lark private_conversations.py 的 module_metric_budget;同一命令在不可变 base 与 head 的完整 450 字节输出相同,相关规则、配置及模块未改,原阈值保留。它是独立告警,不能掩盖本次反例。未查询或等待远端 CI。

原生 Windows 未运行,不能把 POSIX 或模拟分支当作 Windows 资格。10 秒按每次调用重新分配,另有有界清理时间;不是整条 sync 的总 deadline。默认仍不刷新 remote、preview 不发布 integration ref,stdin 从继承改为 DEVNULL 的行为也应作为自动化非交互边界明确保留。

我的整体评价 / Verdict

long_horizon:regression,重复超时可累积失效 worktree 登记;user_experience:regression,返回错误和成功重试都没有揭示或清掉遗留资源。当前必要修复是既有 candidate 生命周期内的清理,不是强制改写到 TypeScript 或增加全局状态。此处未改 rendered presentation,已检查 CLI/plan/Git 生命周期,visual_review 为 not_applicable,未验证范围是原生 Windows、生产采用与长期完整成本。共享词汇、actor 与权限未扩张,架构和代码量基本适配;正确方向及绿色单测仍不能覆盖已复现的生命周期缺口。修复后需在新精确 head 重跑完整 PR 及上述真实反例。

English verdict: REQUEST_CHANGES — timed-out worktree creation leaves a stale registration after recovery.

try:
stdout, stderr = process.communicate(timeout=GIT_READ_TIMEOUT_SECONDS)
except subprocess.TimeoutExpired:
_retire_owned_read(process)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 超时后仍需撤销已产生的 worktree 登记。真实 post-checkout hook 等待11.5秒时,worktree add 已在 common dir 登记,随后被默认10秒预算中断;_build_candidate 尚未执行 added=True,finally 跳过 worktree remove,却删除临时目录。本 head 返回 rc2 后遗留一个 prunable 登记,移除 hook 并成功重试后仍存在;相同 base 成功且没有遗留。请让既有 candidate owner 在 add 部分完成后失败时也清理本次登记,保持原超时并在清理失败时仍收尾目录,避免全局 prune 无关工作。请补真实 Git 回归覆盖超时后的清单、目录、branch/receipt 不变及恢复。

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
@gcl-coder

Copy link
Copy Markdown
Contributor Author

这条 P2 成立,已经按最小范围修了。

根因确认:git worktree add 在 common dir 登记之后才跑 post-checkout。预算在 hook 里耗尽时命令不会返回,_build_candidate 的 added 仍是 False,finally 跳过 worktree remove,随后 rmtree 删掉目录,于是留下一条指向不存在位置的 prunable 登记。

改动:

  • _build_candidate 改为记录“尝试过 add”而不是“add 已成功返回”(attempted)。于是超时、取消、任何在 add 期间抛出的异常都会进入清理分支。
  • 清理顺序固定为:先 git worktree remove --force --force <path>(此时目录还在,登记可被正常撤销),再 rmtree。remove 用 check=False,失败不替换原来的超时。
  • 新增 _prune_missing_candidate():只在本候选路径仍出现在 worktree list 且目录已不存在时,才 worktree prune --expire now 收尾;不触碰其他 worktree。
  • 新增真实 Git 回归 test_a_timed_out_worktree_add_leaves_no_registration:装一个 sleep 3 的 post-checkout,把预算压到 0.4 秒,断言超时后 worktree list 与超时前逐字节相同、没有 prunable、临时根目录已删;移除 hook 后同一 _build_candidate 成功返回且清单仍不变。

本地:tests/capabilities/test_integration_branch.py 与预算文件共 19 项通过。

未覆盖:sync 层的 integration branch 与 last_sync 断言仍在 tests/capabilities/test_integration_branch.py 里跑,我没有在这一次超时用例里重造整条 sync 链路;原生 Windows 依旧未执行。

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

REQUEST_CHANGES:2 个 P2。慢 hook 的旧登记泄漏已修复,但异常清理仍会遗留目录,fallback 还会清理不属于本次操作的 worktree。

精确 head:2f2222868ba4c720d0cbd11dd8d5e59aad3d1391

动机 / Motivation

整合多条 source 分支的开发者需要在 Git helper 卡住时得到可恢复的同步结果。旧同步无限等待,修订给每次 Git 操作设置预算,并试图在超时后清理本次候选 worktree。慢 hook 的旧泄漏已修复,但清理失败与范围反例仍未通过。本 PR 不改变 source refs、远端或 PR 权限;临时资源完整收尾属于当前切片。当前仍缺清理自身失败后收尾、保留原错误和无关登记的保证。

改动思路 / Approach

入口 _git 为既有 integration-branch 的每次 Git 调用设置 10 秒 communicate 等待,并复用 process_runtime.retire_owned_process 回收已拥有进程。这个入口也执行 worktree add/remove、merge 和 update-ref,因此必须处理被中断的部分写入,不能把所有调用按纯读取理解。修订把 added 改成 add 前置的 attempted,能覆盖登记完成但 post-checkout 未结束的情况;remove 的双 --force 可以清理本次锁定 candidate。

原方案不设时限会长期占住同步,单用 timeout 又会留下后代;共享 runtime 加本地 adapter 是合理的较小选择。需要修复的是同一 owner 内的失败收尾和范围,不能用全局 prune 代替本次资源清理。没有必要引入事务框架、新状态或强制语言迁移。

Python 仍是现有 Git provider IO;共享 runtime 负责进程回收,没有新增 Core 决策 owner。当前切片必须在原 owner 内保持原错误、完整清理本次资源并保护无关工作。

具体改动 / Changes

全 PR 是 2 文件,+249/-10;core.py +107/-10,预算测试新增 142 行。本次重新审查整个 base→head,同时单独核对 7a30dba→本 head 的 attempted、remove 和 prune 修订;没有继承上次结论。新增真实 hook 测试只覆盖 remove 正常完成,未覆盖 remove 自身超时及无关失联 worktree。

关键代码讲解

  1. _git L47 保留 UTF-8、原 check 处理和共享回收,新增每次 10 秒等待;check=False 只允许非零退出,不抑制 timeout/OSError,且这不是整条 sync 的总 deadline。
  2. _build_candidate L630 在 add 前记录尝试,并在 finally remove;正常超时现在不留登记。但 L680 的清理异常会提前跳出 finally,使 L690 的目录删除无法执行,且覆盖更早的 add 错误。
  3. _prune_missing_candidate L605 用路径判断是否进入 fallback,但 L626 运行的 Git prune 没有单 worktree 参数。这是条件局部、效果全局,实际删除范围没有被前面的判断限制。

规范依据是不可变 base c63a8f9cfc023ff22f39db5cb8b734da7653e83d 中的 loopx/capabilities/integration_branch/README.md,在读 diff 前已核对,PR 未改其验收边界。configure/boundary 的 preview-first、本地 plan、不 push/source rewrite 均保持;preview-and-sync 的临时资源清理仍未满足。 repository-experience 的既有有用切片建议在当前 head 采用:按用户能够完成的同步/收据任务判断,不把测试数、字段或父路线图完成当作验收。

对主干的风险 / Risks

PASS:78 tests,1 skipped;integration、预算和共享 process runtime 套件。公开 CLI 的 configure preview/execute/replay、drift status、sync preview/execute/replay、in-sync status 和越界 plan 拒绝,共 9 项完整规范化 JSON 与退出码在 base/head 相同。默认 10 秒、真实 post-checkout sleep11.5 反例:base 约13.55秒成功,本 head 约11.01秒明确拒绝且0个失效登记,integration ref 未变;解除 hook 后成功。恢复操作的 updated 标记不同是前置成功/失败状态不同,最终 integration/last_sync 相同,不将其规范成假同值。

[P2] 清理自身超时仍须完成收尾

真实公开 sync + native post-checkout sleep2,PATH wrapper 只把 worktree remove 延迟2秒,测试内每次预算0.4秒。base 完成、无候选遗留;本 head 返回 worktree remove 超时,原 add 超时被覆盖,candidate 目录和登记都仍存在。check=False 无法避免 _git 自己抛错。请在已有 candidate owner 中用嵌套 finally 保证目录收尾,保留原异常/取消,同时如实报告登记清理未确认;新增 remove/list 也失败的真实边界回归。

[P2] 不得为一个候选全局 prune

隔离真实仓库保留一个目录暂时移走、登记已超过两分钟的无关 worktree;native hook 仅删本次 candidate,shell wrapper 拒绝 remove,其余全部交给真实 Git,测试预算1.2秒。base 保留无关登记,本 head 确实执行 worktree prune --expire now 后将它删除。没有 mock 替代清理结果。最初0.4秒 Python wrapper 的探针未能稳定到达目标分支,保留为无效/未触发观察;改用 shell、明确旧登记后复现。请只撤销本次登记,并断言离线/不可达的其他 worktree 在失败和恢复后均保留。

standard premerge 的6项直接检查通过;catalog/risk 合计2项按原生 gate 通过,另有 maintainability advisory FAIL。后者在相同 base/head 的完整450字节输出相同,Lark 模块、规则和配置未改,原阈值保留;它不解释本次已复现的回归。未查询、轮询或等待远端 CI。原生 Windows 未运行;POSIX 模拟分支不能认证原生 Windows。所有写入仅在隔离仓库/夹具;没有用户 Host 安装、付费模型或生产采用测试。

我的整体评价 / Verdict

long_horizon:regression;清理可能遗留本次资源或删除无关登记,反复同步会增加恢复成本。 user_experience:regression;正常流程不增加确认轮次,但失败路径仍不能可靠继续,需要在现有 owner 内修复。架构切片和代码量基本适配,维持 proportionate;方向正确与部分修复通过不能覆盖当前 P2。当前 reviewed prior-head 的慢 hook 泄漏已通过本轮独立重跑,不撤销历史失败,也不自动解决旧讨论。

此处没有 rendered presentation 改动;已检查公开 CLI、provider 和持久收据/清理路径,visual_review 为 not_applicable。未验证范围:原生 Windows、生产 Host 采用、长期完整成本。没有新增共享 enum、actor 或权限;Git-specific 诊断留在 Git provider,没有把产品或 benchmark 条件塞入通用义务。安全范围不变:review 不是 merge、安装或执行模型的授权。修复后需对新精确 head 重跑完整 PR 和上述真实边界反例。

English verdict: REQUEST_CHANGES — 2f22228; two reproducible cleanup defects remain after the original hook leak was fixed.

# Remove this candidate's own registration while its directory
# still exists; a cleanup failure must not replace the timeout or
# cancellation that ended the attempt.
_git(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 清理命令也会超时,check=False 不会抑制 _git 的 IntegrationBranchError。真实公开 sync 中,post-checkout 等待2秒,wrapper 仅延迟 worktree remove 2秒,测试预算0.4秒:返回的错误变成 remove 超时,原 add 超时被覆盖;L690 的 rmtree 未执行,candidate 目录和登记均留下。请在现有 owner 中用嵌套 finally 保证目录收尾,保留原异常/取消,并如实保留登记回收未确认的状态;补 remove/list 自身失败及恢复的真实 Git 回归。

if resolved != target:
continue
if not candidate.exists():
_git(repo, "worktree", "prune", "--expire", "now", check=False)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 前面的候选路径匹配只限制何时进入分支,不能限制 git worktree prune 的效果;此命令没有单路径参数,会删除 common dir 中所有符合条件的失联 worktree 登记。真实公开 sync 夹具中,native hook 只删除本次 candidate,shell wrapper 拒绝 candidate remove;一个目录暂时移走、登记已较旧的无关 worktree 在 base 保留,而本 head 执行这里后将其删除。请只撤销本次拥有的 candidate 登记,避免全局 prune,并回归断言其他离线 worktree 在失败与恢复后仍保留。

…er worktrees

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
@gcl-coder

Copy link
Copy Markdown
Contributor Author

两条 P2 都修了,新 head 需重看。

P2-1 清理命令自身超时。 _retire_candidate_worktree 现在把 git worktree remove 的超时和非零退出都收在自己这里,候选目录删除放进 finally,之后才做登记收尾,所以清理的失败不会跳过目录、也不会替换正在展开的原始错误或取消。真实反例(post-checkout sleep 2、wrapper 让 worktree remove 延迟 2 秒、预算 0.4 秒)新 head 返回的仍是 add 的 did not answer within 0.4 seconds,scratch 目录已消失,git worktree list --porcelain 与基线逐字节一致;移除 hook 后重试成功,清单不变。另加一条真实夹具:worktree remove 与 rev-parse --git-common-dir 同时失败时,目录照样收尾,异常原样抛出,并附 note 说明本次登记未撤销、清单会以 prunable 显示,不会把它算作清理成功。

P2-2 全局 prune。 已删除 git worktree prune --expire now。新增的 _unregister_candidate 只撤销本次候选:读 <common>/worktrees/*/gitdir 指针,按本候选 checkout 路径匹配,只删这一个 admin 条目。真实夹具里先建一个目录已移走、登记已陈旧的无关 worktree,再用 wrapper 让 remove 返回非零:base 保留该登记,新 head 也保留,只有本候选的登记消失。

覆盖:tests/capabilities/test_integration_branch_git_budget.py 7 项(新增 3 条真实 Git 回归),与 tests/capabilities/test_integration_branch.py 合计 22 passed。原生 Windows 仍未执行;POSIX wrapper 只覆盖逻辑分支,不作为 Windows 资格。树的其余内容未改。

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

APPROVE:本 head 未发现阻断项。上轮发现已用当前版本的真实入口重新验证,以下结论覆盖完整 PR。

精确 head:2cb8ca0300948d0a918be3707c98ffe1ed397176

动机 / Motivation

整合多个 source 分支的开发者需要在 Git helper 卡住时结束本次同步,并能安全重试。旧同步可无限等待;直接中断 worktree add 又可能留下部分登记。本 head 将等待限制在每次 Git 调用,并只清理本次候选。真实超时不再遮蔽原错误,候选目录和自身登记得到清理,无关失联登记保留,解除故障后可继续同步。不改动会继续保留已复现的等待或文件身份问题;验证对象是开发者能否完成原任务、看见失败并重试,而不是仅检查 helper 返回或测试数量。本 PR 不增加远端写入、合并、安装、模型执行或额外调用权限;原生 Windows 与生产长期收益不在本地资格内。

改动思路 / Approach

共享 runtime 负责进程生命周期;本能力负责 Git 的文本/错误合同和本次 detached candidate 的退役。新增的本地收尾并未成为第二个 Core 决策 owner。只加 timeout 会留下部分 worktree;全局 prune 又会越过本次范围。当前把这两段在同一 owner 内一起闭合,是可独立验收的较小切片。

Git/文件名/目录清理属于现有 Python provider IO;进程回收复用共享 runtime,资格决策仍归原 typed owner。本切片闭合每次 Git 等待、部分候选收尾和本次资源范围,后续不需要新事务框架。最强反对理由是预算可能拒绝合法慢操作、额外清理需要理解 Git 元数据,以及路径 codec 必须同时守住越界边界;这些成本已由现有 owner 和对应真实反例验证约束。没有新增安装、配置、确认或信息重填轮次。

具体改动 / Changes

本 PR 全量为2文件,+477/-10。另单独核对上一评审 head 到当前 head 的修复:2f222286 的 cleanup timeout/global prune 两项已改为嵌套收尾及候选精确匹配。历史失败保持其原有结论,没有将其重写为通过,也没有继承上次批准趋势。

关键代码讲解

  1. _git L47 使用 Popen/communicate,每次等待10秒;timeout 与取消进入共享 retire_owned_process,正常 UTF-8、退出码及 check 语义保留。此入口也执行 merge、fetch、update-ref,所以预算不是只读专用,更不是整条 sync 的总上限。

  2. _retire_candidate_worktree L642 把 remove 的非零退出、超时和启动失败留在本地收尾;目录删除放在 finally,原 add 错误继续传播。

  3. _unregister_candidate L605 通过 Git common dir 下每个 gitdir 指针匹配本候选的 .git 路径,只删除匹配项,替代没有单路径参数的 global prune。

  4. _build_candidate L678 在 add 前标记 attempted,覆盖登记已写但 hook 未结束的状态;finally 无论 add 是否返回都退役本次资源。双重 IO 故障仍可能留下可见的 prunable 登记,不能将它称为清理成功。

规格依据:loopx/capabilities/integration_branch/README.md;spec_revision:c63a8f9cfc023ff22f39db5cb8b734da7653e83d。Configure、Preview-and-sync、Boundary 在本 head 均为 implemented,分别映射到上述现有入口、完整 CLI 正反例和持久状态读回。它们指向原 README 的章节/编号步骤,不新增父级 roadmap 门槛。

对主干的风险 / Risks

PASS:integration 与共享 process runtime 集合81 passed、1 skipped。9项 ordinary configure/status/preview/execute/replay/越界拒绝的完整规范化 JSON 和退出码均与 base 相同。默认10秒、真实 post-checkout sleep11.5:base 约13.63秒完成,head 约11.44秒拒绝,integration ref 未变、无失效登记;解除 hook 后成功。

上轮两项 P2 重新独立验证:实际公开 sync、真实 hook sleep2、shell wrapper 仅延迟或拒绝 remove,测试内每次预算0.8秒。head 返回原 add 超时,candidate 目录消失,worktree 清单与调用前一致;加入一个目录暂时移走且登记已较旧的无关 worktree 后,其登记仍保留。没有 mock 提供这些后置状态。

同时拒绝 remove 和 common-dir 读取时,目录仍删除、原错误保留、plan/ref 不变,但登记不能确认撤销。这个残余如实保留;异常 note 也不会自动成为公开 CLI JSON 字段。正常重试的成功不被当作磁盘/权限失败已自动修复。

原生 standard premerge 的6项直接检查和2项选择检查通过 gate。首次运行因工作树缺 TypeScript 开发依赖失败,已保留失败记录,安装 npm ci --ignore-scripts 后在相同未改 head 重跑通过。另有原 Lark 模块 metric advisory FAIL:当前 base/head 完整450字节输出一致,相关模块、oracle、配置与阈值未变;没有把它改成 PASS。未查询或等待远端 CI。

我的整体评价 / Verdict

long_horizon:improved;真实超时不再遮蔽原错误,候选目录和自身登记得到清理,无关失联登记保留,解除故障后可继续同步。 user_experience:improved;原有入口、关闭/预览态与普通重放不增加操作轮次,失败后由原 caller 继续。这里的改善限定于验证过的本地任务和恢复,不宣称已测得生产 token、费用或长期净收益。

代码规模与已复现问题相称,判为 proportionate;把 candidate 退役集中到本地 helper 并删除 global prune,完成同域简化。Git admin fallback 仍需后续平台兼容回归。没有 rendered presentation 改动;已检查公开 CLI、Git provider 及持久收据/候选清理旅程。未验证范围:原生 Windows、生产 Host 采用、长期完整成本与收益。共享 typed vocabulary、权限和通用义务不变。评审结论与旧 blocking review 的正式状态、readiness 及维护者合并决定分别处理。

English verdict: APPROVE — 2cb8ca0; bounded Git and scoped candidate recovery pass the current whole-PR checks.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants